#!/usr/bin/env bash
# Usage: script/mirror update <COMMIT-RANGE>
#        script/mirror verify <COMMIT-RANGE>
#        script/mirror stats
set -e

eval "$(grep RUBY_BUILD_MIRROR_URL= ./bin/ruby-build | head -1)"

help_text() {
  sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0"
}

test_mirrored() {
  curl -qsSfIL "$RUBY_BUILD_MIRROR_URL/$1" >/dev/null 2>&1
}

compute_sha2() {
  local output
  output="$(openssl dgst -sha256)"
  tr '[:upper:]' '[:lower:]' <<<"${output##* }"
}

download_package() {
  curl -qsSfL -o "$2" "$1"
}

download_and_verify() {
  local checksum
  local url="$1"
  local file="$2"
  local expected="$3"
  download_package "$url" "$file"
  checksum="$(compute_sha2 < "$file")"
  if [ "$checksum" != "$expected" ]; then
    echo "Error: $url doesn't match its checksum $expected" >&2
    return 1
  fi
}

changed_files() {
  git diff --name-only --diff-filter=ACMR "$@"
}

potentially_new_packages() {
  local head="${1#*..}"
  local files
  IFS=$'\n' read -d '' -r -a files < <(changed_files "$1" -- ./share/ruby-build)
  [ ${#files[@]} -gt 0 ] || return 0
  extract_urls "${head:-HEAD}" -- "${files[@]}"
}

extract_urls() {
  git grep -hoe 'http[^"]\+#[^"]\+' "$@" | sort | uniq
}

update() {
  local url
  local checksum
  local file
  local tmp_path
  for url in $(potentially_new_packages "$1"); do
    checksum="${url#*#}"
    url="${url%#*}"
    if test_mirrored "$checksum"; then
      echo "Already mirrored: $url"
    else
      echo "Will mirror: $url"
      [ -n "$tmp_path" ] || tmp_path="$(mktemp -d "${TMPDIR:-/tmp}/s3-sync.XXXXX")"
      file="$tmp_path/$checksum"
      download_and_verify "$url" "$file" "$checksum"
    fi
  done
  if [ -n "$tmp_path" ]; then
    echo "Uploading..."
    aws s3 sync --acl=public-read --size-only --no-progress "$tmp_path" "s3://${AMAZON_S3_BUCKET?}"
  fi
}

verify() {
  local url
  local checksum
  local file
  local status=0
  for url in $(potentially_new_packages "$1"); do
    checksum="${url#*#}"
    url="${url%#*}"
    echo "Verifying checksum for $url"
    file="${TMPDIR:-/tmp}/$checksum"
    download_and_verify "$url" "$file" "$checksum" || status=$?
  done
  return $status
}

stats() {
  local packages
  IFS=$'\n' read -d '' -r -a packages < <(extract_urls -- ./share/ruby-build/\*)
  local total="${#packages[@]}"
  local confirmed=0
  local checksum
  for url in "${packages[@]}"; do
    checksum="${url#*#}"
    if test_mirrored "$checksum"; then
      : $((confirmed++))
    else
      echo "failed: $url" >&2
    fi
    echo -n "."
  done
  echo
  echo "$confirmed/$total mirrored"
}

cmd="$1"

case "$cmd" in
update | verify | stats )
  shift 1
  "$cmd" "$@"
  ;;
-h | --help )
  help_text
  exit 0
  ;;
* )
  help_text >&2
  exit 1
  ;;
esac
